﻿//EquityCurveChart.xaml.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Xaml
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.Windows.Data;
	using System.Windows.Media;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Shapes;

	using Abt.Controls.SciChart;

	using Ecng.Collections;
	using Ecng.Xaml;

	/// <summary>
	/// Графический компонент отображения кривой эквити.
	/// </summary>
	public partial class EquityCurveChart
	{
		private sealed class EquityCurveItemList : BaseList<EquityData>
		{
			private readonly EquityCurveChart _parent;
			private readonly object _lock = new object();
			private List<DateTime> _bufferDates = new List<DateTime>();
			private List<double> _bufferValues = new List<double>();

			public EquityCurveItemList(EquityCurveChart parent, IDataSeries<DateTime, double> series)
			{
				if (parent == null)
					throw new ArgumentNullException("parent");

				if (series == null)
					throw new ArgumentNullException("series");

				_parent = parent;
				Series = series;

				GuiDispatcher.GlobalDispatcher.AddPeriodicalAction(OnTimer);
			}

			public IDataSeries<DateTime, double> Series { get; private set; }

			private void OnTimer()
			{
				List<DateTime> dates;
				List<double> values;

				lock (_lock)
				{
					dates = _bufferDates;
					values = _bufferValues;
					_bufferDates = new List<DateTime>();
					_bufferValues = new List<double>();
				}

				if (dates.Count > 0)
				{
					Series.Append(dates, values);

					if (!_parent.sciChart.ChartModifier.IsEnabled)
						_parent.sciChart.ChartModifier.IsEnabled = true;
				}
			}

			protected override bool OnAdding(EquityData item)
			{
				lock (_lock)
				{
					_bufferDates.Add(item.Time);
					_bufferValues.Add((double)item.Value);
				}

				return base.OnAdding(item);
			}

			protected override bool OnClearing()
			{
				lock (_lock)
				{
					_bufferDates = new List<DateTime>();
					_bufferValues = new List<double>();
				}
				
				GuiDispatcher.GlobalDispatcher.AddAction(() => Series.Clear());

				return base.OnClearing();
			}
		}

		private readonly DataSeriesSet<DateTime, double> _dataSet = new DataSeriesSet<DateTime, double>();
		private bool _inZoom;
		private readonly Dictionary<IDataSeries, FastMountainRenderableSeries> _dicCurve = new Dictionary<IDataSeries, FastMountainRenderableSeries>();

		/// <summary>
		/// Стиль отрисовки кривой эквити.
		/// </summary>
		public EquityCurveChartStyles EquityStyle { get; set; }

		/// <summary>
		/// Создать <see cref="EquityCurveChart"/>.
		/// </summary>
		public EquityCurveChart()
		{
			InitializeComponent();

			EquityStyle = EquityCurveChartStyles.Line;

			sciChart.DataSet = _dataSet;

			sciChart.PreviewMouseWheel += (sender, args) =>
			{
				if (!sciChart.ChartModifier.IsEnabled || _inZoom || args.Delta <= 0)
					return;

				_inZoom = true;
				EnableInteractivity(true);
			};

			sciChart.PreviewMouseDoubleClick += (sender, args) =>
			{
				if (!sciChart.ChartModifier.IsEnabled || !_inZoom)
					return;

				_inZoom = false;
				EnableInteractivity(false);
			};

			EnableInteractivity(false);

			using (sciChart.SuspendUpdates())
			using (sciChart.XAxis.SuspendUpdates())
			{
				sciChart.ChartModifier.IsEnabled = false;
				sciChart.XAxis.VisibleRange = null;
			}
		}

        static EquityCurveChart()
        {
            MsChartEx.InitChartSettings();
        }

		/// <summary>
		/// Создать новую кривую для отрисовки доходности.
		/// </summary>
		/// <param name="title">Заголовок кривой.</param>
		/// <param name="color">Цвет кривой.</param>
		/// <returns>Коллекция с данными, которую необходимо заполнять для отрисовки кривой.</returns>
		public ICollection<EquityData> CreateCurve(string title, Color color)
		{
			var series = _dataSet.AddSeries();
			series.SeriesName = title;

			var fillColor = new Color();

			switch (EquityStyle)
			{
				case EquityCurveChartStyles.Area:
					fillColor = new Color { ScA = 0.8f, R = color.R, G = color.G, B = color.B };
					break;

				case EquityCurveChartStyles.Line:
					fillColor = new Color { ScA = 0f, R = color.R, G = color.G, B = color.B };
					break;
			}

			var renderSeries = new FastMountainRenderableSeries
			{
				SeriesColor = color,
				AntiAliasing = true,
				AreaColor = fillColor,
				DataSeries = series
			};

			var template = new ControlTemplate { VisualTree = new FrameworkElementFactory(typeof(Ellipse)) };
			template.VisualTree.SetValue(WidthProperty, 8D);
			template.VisualTree.SetValue(HeightProperty, 8D);
			template.VisualTree.SetValue(Shape.FillProperty, new SolidColorBrush(color));
			template.VisualTree.SetValue(Shape.StrokeProperty, Brushes.Lavender);
			template.VisualTree.SetValue(Shape.StrokeThicknessProperty, 2D);

			renderSeries.RolloverMarkerTemplate = template;
			sciChart.RenderableSeries.Add(renderSeries);

			_dicCurve.Add(series, renderSeries);

			return new EquityCurveItemList(this, series);
		}

		/// <summary>
		/// Удалить кривую доходности с графика.
		/// </summary>
		/// <param name="items">Коллекция с данными, полученная из метода <see cref="CreateCurve"/>.</param>
		public void RemoveCurve(ICollection<EquityData> items)
		{
			if (items == null)
				throw new ArgumentNullException("items");

			if (_dataSet.IsEmpty())
				return;

			var series = ((EquityCurveItemList)items).Series;
			var renderableSeries = _dicCurve[series];

			_dataSet.Remove(series);
			sciChart.RenderableSeries.Remove(renderableSeries);

			_dicCurve.Remove(series);
		}

		private void EnableInteractivity(bool enable)
		{
			sciChart.XAxis.AutoRange = !enable;

			if (enable)
				sciChart.ChartModifier = _groupModifier;
			else
				sciChart.ChartModifier = rolloverModifier;
		}
	}

	class DateTimeToStringConverter : IValueConverter
	{
		//private readonly Logger _log = new Logger("xval_conv");

		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (!(value is DateTime))
			{
				//_log.AddWarningLog("XValue type is wrong: {0}", value.GetType().Name);
				return string.Empty;
			}

			var dt = (DateTime)value;
			return string.Format("{0:d MMM yyyy, HH:mm}", dt);
		}

		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
	}
}